package java_thinking.unit_21._21_6;

import java.util.*;
import java.util.concurrent.*;

/**
 * @Desc:   6-17 在预定时间内请求旅游报价
 *          1.InvokeAll方法的参数为一组任务，并返回一组Future。这两个集合有着相同的结构。
 *            InvokeAll按照任务集合中迭代器的顺序将所有的Future添加到返回的集合中，从而
 *            使调用者能将各个Future与其表示Callable关联起来。当所有任务都执行完毕时，
 *            或者调用线程被中断时，又或者超过指定时限时，invokeAll将返回。将超过指定时
 *            限后，任何还未完成的任务都会被取消。当invokeAll返回后，每个任务要么正常地
 *            完成，要么被取消，没有正在执行的任务，而客户端可以调用get或isCancelled来判
 *            断究竟是何种情况。
 * @author: cww
 * @DateTime: 2019/6/12 20:01
 */

public class TimeBudget {
    private static ExecutorService exec = Executors.newCachedThreadPool();
    public List<TravelQuote> getRankedTravelQuote(TravelInfo travelInfo,
                                                  Set<TravelCompany> companies,
                                                  Comparator<TravelQuote> ranking,
                                                  long time, TimeUnit unit) throws InterruptedException {
        List<QuoteTask> tasks = new ArrayList<>();
        for (TravelCompany company : companies) {
            tasks.add(new QuoteTask(company, travelInfo));
        }
        /**
         * 支持显示的 invokeAll ，将多个任务提交到一个 ExecutorService 中并获得结果
         * 按照任务集合 tasks 中的迭代器顺序将所有的 Future 添加到返回的集合中，从而使调用者能
         * 将各个 Future 与其表示的 Callable 关联起来
         */
        List<Future<TravelQuote>> futures = exec.invokeAll(tasks,time,unit);
        List<TravelQuote> quotes = new ArrayList<>(tasks.size());
        Iterator<QuoteTask> taskIterator = tasks.iterator();
        for (Future<TravelQuote> future : futures) {
            QuoteTask task = taskIterator.next();
            try {
                quotes.add(future.get());
            } catch (ExecutionException e) {
                quotes.add(task.getFailureQuote(e.getCause()));
            } catch (CancellationException e) {
                quotes.add(task.getTimeoutQuote(e));
            }
        }
        Collections.sort(quotes, ranking);
        return quotes;
    }



}
class QuoteTask implements Callable<TravelQuote> {
    private final TravelCompany company;
    private final TravelInfo travelInfo;

    public QuoteTask(TravelCompany company, TravelInfo travelInfo) {
        this.company = company;
        this.travelInfo = travelInfo;
    }
    TravelQuote getFailureQuote(Throwable t) {
        return null;
    }

    TravelQuote getTimeoutQuote(CancellationException e) {
        return null;
    }

    /**
     * 请求报价线程
     * @return
     * @throws Exception
     */
    @Override
    public TravelQuote call() throws Exception {
        return company.solicitQuote(travelInfo);
    }
}
interface TravelCompany {
    TravelQuote solicitQuote(TravelInfo travelInfo) throws Exception;
}

interface TravelQuote {
}

interface TravelInfo {
}